package com.wheelersoftware.springsecurity;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.security.AccessDeniedException;
import org.springframework.security.Authentication;
import org.springframework.security.ConfigAttribute;
import org.springframework.security.ConfigAttributeDefinition;
import org.springframework.security.SecurityConfig;
import org.springframework.security.vote.AbstractAccessDecisionManager;
import org.springframework.security.vote.AccessDecisionVoter;

/*
 * Author       :       Willie Wheeler and John Wheeler
 * Book         :       'Spring In Practice' [Book written by Willie Wheeler and John Wheeler]
 */
public class LogicalBased extends AbstractAccessDecisionManager {
    private static final Log logger = LogFactory.getLog(LogicalBased.class);

	public void decide(Authentication authentication, Object object,
			ConfigAttributeDefinition config) throws AccessDeniedException {
		
		logger.debug("Deciding: authentication=" + authentication +
				", object=" + object + ", config=" + config);
		
		ConfigAttribute adminAttr = new SecurityConfig("ROLE_ADMIN");
		ConfigAttribute studentAttr = new SecurityConfig("ROLE_STUDENT");
		ConfigAttribute authAttr = new SecurityConfig("IS_AUTHENTICATED_FULLY");
		
		boolean admin = false;
		boolean student = false;
		boolean auth = false;
		
		for (Object v : getDecisionVoters()) {
			AccessDecisionVoter voter = (AccessDecisionVoter) v;
			
			int adminResult = voter.vote(authentication, object, new ConfigAttributeDefinition(adminAttr));
			if (adminResult == AccessDecisionVoter.ACCESS_GRANTED) {
				admin = true;
			}
			
			int studentResult = voter.vote(authentication, object, new ConfigAttributeDefinition(studentAttr));
			if (studentResult == AccessDecisionVoter.ACCESS_GRANTED) {
				student = true;
			}
			
			int authResult = voter.vote(authentication, object, new ConfigAttributeDefinition(authAttr));
			if (authResult == AccessDecisionVoter.ACCESS_GRANTED) {
				auth = true;
			}
		}
		
		if (!(admin || (student && auth))) {
			throw new AccessDeniedException(messages.getMessage(
				"AbstractAccessDecisionManager.accessDenied",
				"Access is denied"));
		}
	}
}
